<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>令牌桶轮转演示</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      background: #f5f7fa;
      margin: 0;
      padding: 20px;
      display: flex;
      flex-direction: column;
      align-items: center;
    }

    h1 {
      color: #333;
      margin-bottom: 20px;
    }

    .container {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 30px;
    }

    .bucket {
      width: 120px;
      height: 150px;
      background: #4CAF50;
      border-radius: 10px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: flex-end;
      color: white;
      font-weight: bold;
      position: relative;
      box-shadow: 0 4px 8px rgba(0,0,0,0.2);
    }

    .bucket::before {
      content: "令牌桶";
      position: absolute;
      top: 10px;
      font-size: 14px;
    }

    .token {
      width: 20px;
      height: 20px;
      background: gold;
      border-radius: 50%;
      margin-bottom: 4px;
      box-shadow: 0 0 6px gold;
    }

    .consumers {
      display: flex;
      gap: 40px;
    }

    .consumer {
      width: 100px;
      height: 120px;
      background: #2196F3;
      border-radius: 8px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: flex-end;
      color: white;
      position: relative;
      box-shadow: 0 4px 8px rgba(0,0,0,0.2);
    }

    .consumer::before {
      content: attr(data-name);
      position: absolute;
      top: 10px;
      font-size: 16px;
      font-weight: bold;
    }

    .controls {
      margin-top: 20px;
    }

    button {
      padding: 8px 16px;
      margin: 0 5px;
      font-size: 14px;
      cursor: pointer;
    }

    .info {
      margin-top: 15px;
      color: #555;
      font-size: 14px;
      text-align: center;
    }
  </style>
</head>
<body>
  <h1>令牌桶轮转分配演示</h1>

  <div class="container">
    <div class="bucket" id="bucket"></div>

    <div class="consumers" id="consumers">
      <!-- 消费者 A, B, C 将由 JS 动态生成 -->
    </div>
  </div>

  <div class="controls">
    <button onclick="toggleRunning()">暂停/继续</button>
    <button onclick="reset()">重置</button>
  </div>

  <div class="info">
    <p>令牌以每秒 2 个的速度生成，按 A → B → C → A ... 顺序轮转分配</p>
  </div>

  <script>
    // 配置
    const CONSUMERS = ['A', 'B', 'C'];
    const TOKEN_GENERATE_RATE = 500; // 毫秒，即每秒 2 个
    const ANIMATION_DURATION = 600; // 令牌移动动画时间（毫秒）

    let bucketTokens = [];
    let consumerTokens = { A: [], B: [], C: [] };
    let currentConsumerIndex = 0;
    let isRunning = true;
    let tokenCounter = 0;

    const bucketEl = document.getElementById('bucket');
    const consumersEl = document.getElementById('consumers');

    // 初始化消费者 DOM
    function initConsumers() {
      consumersEl.innerHTML = '';
      CONSUMERS.forEach(name => {
        const div = document.createElement('div');
        div.className = 'consumer';
        div.dataset.name = name;
        div.id = `consumer-${name}`;
        consumersEl.appendChild(div);
      });
    }

    // 创建令牌元素
    function createTokenElement(id) {
      const token = document.createElement('div');
      token.className = 'token';
      token.id = `token-${id}`;
      return token;
    }

    // 从桶中取出一个令牌并分配给当前消费者
    function distributeToken() {
      if (bucketTokens.length === 0 || !isRunning) return;

      const tokenId = bucketTokens.shift();
      const tokenEl = document.getElementById(`token-${tokenId}`);
      if (!tokenEl) return;

      const consumerName = CONSUMERS[currentConsumerIndex];
      const consumerEl = document.getElementById(`consumer-${consumerName}`);

      // 动画：从桶移动到消费者
      const bucketRect = bucketEl.getBoundingClientRect();
      const consumerRect = consumerEl.getBoundingClientRect();
      const containerRect = document.querySelector('.container').getBoundingClientRect();

      // 临时定位到桶底部
      tokenEl.style.position = 'absolute';
      tokenEl.style.left = (bucketRect.left - containerRect.left + bucketRect.width / 2 - 10) + 'px';
      tokenEl.style.top = (bucketRect.top - containerRect.top + bucketRect.height - 20) + 'px';
      document.body.appendChild(tokenEl);

      // 执行动画
      setTimeout(() => {
        tokenEl.style.transition = `left ${ANIMATION_DURATION}ms, top ${ANIMATION_DURATION}ms`;
        tokenEl.style.left = (consumerRect.left - containerRect.left + consumerRect.width / 2 - 10) + 'px';
        tokenEl.style.top = (consumerRect.top - containerRect.top + consumerRect.height - 20) + 'px';

        setTimeout(() => {
          // 动画结束后放入消费者容器
          consumerEl.appendChild(tokenEl);
          tokenEl.style.position = '';
          tokenEl.style.left = '';
          tokenEl.style.top = '';
          tokenEl.style.transition = '';

          // 记录
          consumerTokens[consumerName].push(tokenId);
          // 轮转到下一个消费者
          currentConsumerIndex = (currentConsumerIndex + 1) % CONSUMERS.length;
        }, ANIMATION_DURATION);
      }, 10);
    }

    // 生成令牌（放入桶）
    function generateToken() {
      if (!isRunning) return;
      tokenCounter++;
      const tokenEl = createTokenElement(tokenCounter);
      bucketTokens.push(tokenCounter);
      bucketEl.appendChild(tokenEl);
    }

    // 启动定时器
    function start() {
      setInterval(generateToken, TOKEN_GENERATE_RATE);
      setInterval(distributeToken, 300); // 尝试分配（比生成快，避免堆积）
    }

    function toggleRunning() {
      isRunning = !isRunning;
    }

    function reset() {
      bucketTokens = [];
      consumerTokens = { A: [], B: [], C: [] };
      currentConsumerIndex = 0;
      tokenCounter = 0;
      bucketEl.innerHTML = '';
      CONSUMERS.forEach(name => {
        document.getElementById(`consumer-${name}`).innerHTML = '';
      });
    }

    // 初始化
    initConsumers();
    start();
  </script>
</body>
</html>